<?php
/*
 * 实现网络连接，PHP服务器端模拟GET请求和POST请求
 */
class HttpClient{
    /* Contains the last HTTP status code returned. */
    public $http_code;

    private $base_uri;

    /* Contains the last API call. */
    public $url;

    /* Set timeout default. */
    public $timeout = 30;

    /* Set connect timeout. */
    public $connecttimeout = 30;

    /* Verify SSL Cert. */
    public $ssl_verifypeer = FALSE;

    /* Respons format. */
    public $format = 'json';

    /* Decode returned json data. */
    public $decode_json = TRUE;

    /* Contains the last HTTP headers returned. */
    public $http_info;

    /* Set the useragnet. */
    public $useragent = 'KX PHPSDK API v2.0.1';

    public function __construct($base_uri=''){
        $this->base_uri = $base_uri?$base_uri:C('API_URI');
    }

    /**
     * @param $params  参数数组
     * @return string
     * 根据参数获取头信息
     * 20140325添加方法
     */
    private function buildHeaders($params){
        return '';
//        $headers = array();
//        if(isset($params['access_token']) && !empty($params['access_token'])){
//            $headers[] ='Authorization:OAuth OAuth="'.$params['access_token'].'"';
//        }
//
//        $header = implode("\r\n", $headers);
//        unset($headers);
//
//        return $header;
    }

    /**
     * @param $url 请求URL
     * @param array $params 请求参数
     * @return mixed
     * GETy请求
     */
    public function get($url, $params = array())
    {
        $url .= "?".OAuthUtil::build_http_query($params);
        $header = $this->buildHeaders($params);
        $response = $this->http($url,'GET','',false,$header);

//    	if ($this->format === 'json' && $this->decode_json) {
//      		return json_decode($response);
//    	}
        return $response;
    }

    /**
     * @param $url 请求URL
     * @param array $params 请求参数
     * @param bool $multi
     * @return API|mixed
     * POST请求
     */
    function post($url, $params = array(), $multi = false) {
        $query = "";
        if($multi){
            $query = OAuthUtil::build_http_query_multi($params);
        } else {
            $query = OAuthUtil::build_http_query($params);
        }

        $header = $this->buildHeaders($params);
        $response = $this->http($url,'POST',$query,$multi,$header);

//	    if ($this->format === 'json' && $this->decode_json) {
//            return json_decode($response);
//	    }
        return $response;
    }


    /**
     * Make an HTTP request
     *
     * @return API results
     */
    function http($url, $method, $postfields = NULL, $multi = false,$header='') {
        $this->http_info = array();
        $ci = curl_init();
        /* Curl settings */
        curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
        curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
        curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:',$header));
        curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
        curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ci, CURLOPT_HEADER, FALSE);

        switch ($method) {
            case 'POST':
                curl_setopt($ci, CURLOPT_POST, TRUE);
                if (!empty($postfields)) {
                    curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
                }
                break;
            case 'DELETE':
                curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
                if (!empty($postfields)) {
                    $url = "{$url}?{$postfields}";
                }
        }

        if( $multi )
        {
            $header_array = array("Content-Type: multipart/form-data; boundary=" . OAuthUtil::$boundary , "Expect: ",$header);
            curl_setopt($ci, CURLOPT_HTTPHEADER, $header_array );
            curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );
        }

        curl_setopt($ci, CURLOPT_URL, $url);
        $response = curl_exec($ci);
        $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
        $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
        $this->url = $url;
        curl_close ($ci);
        return $response;
    }

    /**
     * @param $path 相对路径
     * @param string $method 请求方法类型
     * @param array $params 参数
     * 调用api方法
     */
    public function api($path, $method = 'GET', $params = array()) {
        //如果$method是数组，而且$params为空，那么请求方法类型为默认的GET，而参数数组就是$method
        if (is_array($method) && empty($params)) {
            $params = $method;
            $method = 'GET';
        }

        //对参数数组中所有非字符串的元素进行json编码
        foreach ($params as $key => $value) {
            if (!is_string($value)) {
                $params[$key] = json_encode($value);
            }
        }

        $url = $this->getUri($path);//获取URI

        //调用相应请求方法
        switch(strtoupper($method)){
            case 'GET':
                $result = $this->get($url,$params);
                break;

            default:
                $result = $this->post($url,$params);
        }

//        if (is_array($result) && isset($result['error'])) {
//            $e = new OAuth2Exception($result);
//            throw $e;
//        }

        return $result;
    }

    /**
     * @param $path 相对路径
     * @return mixed|string
     * 根据相对路径获取绝对网址路径
     */
    private function getUri($path){
        $url = $this->base_uri;

        if (!empty($path)){
            if (substr($path, 0, 4) == "http"){
                $url = $path;
            } else{
                $url = rtrim($url, '/') . '/' . ltrim($path, '/');
            }
        }

        return $url;
    }
}

/*
 * URL处理类
 */
class OAuthUtil {
    public static $boundary = '';

    /**
     * @param $input 要编码的字符串或数组
     * @return array|mixed|string
     * 对数组或字符串进行编码
     */
    public static function urlencode_rfc3986($input) {
        if (is_array($input)) {
            return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);//20140609修改，添加命名空间
        } else if (is_scalar($input)) {
            return str_replace(
                '+',
                ' ',
                str_replace('%7E', '~', rawurlencode($input))
            );
        } else {
            return '';
        }
    }


    // This decode function isn't taking into consideration the above
    // modifications to the encoding process. However, this method doesn't
    // seem to be used anywhere so leaving it as is.
    /**
     * @param $string 要解码的字符串
     * @return string
     * 字符串解码，与urlencode_rfc3986相对
     */
    public static function urldecode_rfc3986($string) {
        return urldecode($string);
    }

    /**
     * @param $params 参数数组
     * @return string
     * 生成URL格式的字符串并返回
     */
    public static function build_http_query($params) {
        if (!$params) return '';

        // Urlencode both keys and values
        $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
        $values = OAuthUtil::urlencode_rfc3986(array_values($params));
        $params = array_combine($keys, $values);

        // Parameters are sorted by name, using lexicographical byte value ordering.
        // Ref: Spec: 9.1.1 (1)
        uksort($params, 'strcmp');

        $pairs = array();
        foreach ($params as $parameter => $value) {
            if (is_array($value)) {
                // If two or more parameters share the same name, they are sorted by their value
                // Ref: Spec: 9.1.1 (1)
                natsort($value);
                foreach ($value as $duplicate_value) {
                    $pairs[] = $parameter . '=' . $duplicate_value;
                }
            } else {
                $pairs[] = $parameter . '=' . $value;
            }
        }

        // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
        // Each name-value pair is separated by an '&' character (ASCII code 38)
        return implode('&', $pairs);
    }

    /**
     * @param $params 参数数组
     * @return string
     * 生成URL格式的字符串并返回
     */
    public static function build_http_query_multi($params) {
        if (!$params) return '';

        // Urlencode both keys and values
        $keys = array_keys($params);
        $values = array_values($params);
        $params = array_combine($keys, $values);

        // Parameters are sorted by name, using lexicographical byte value ordering.
        // Ref: Spec: 9.1.1 (1)
        uksort($params, 'strcmp');
        $pairs = array();
        self::$boundary = $boundary = uniqid('------------------');
        $MPboundary = '--'.$boundary;
        $endMPboundary = $MPboundary. '--';
        $multipartbody = '';

        foreach ($params as $parameter => $value)
        {
            if( in_array($parameter,array("pic","image")) && $value{0} == '@' )
            {
                $url = ltrim( $value , '@' );
                $content = file_get_contents( $url );
                $filename = reset( explode( '?' , basename( $url ) ));
                $mime = self::get_image_mime($url);

                $multipartbody .= $MPboundary . "\r\n";
                $multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename . '"'. "\r\n";
                $multipartbody .= 'Content-Type: '. $mime . "\r\n\r\n";
                $multipartbody .= $content. "\r\n";
            }
            else
            {
                $multipartbody .= $MPboundary . "\r\n";
                $multipartbody .= 'content-disposition: form-data; name="'.$parameter."\"\r\n\r\n";
                $multipartbody .= $value."\r\n";
            }
        }
        $multipartbody .=  $endMPboundary;
        return $multipartbody;

    }

    /**
     * @param $file
     * @return string
     * 获取MIME类型
     */
    public static function get_image_mime( $file ){
        $ext = strtolower(pathinfo( $file , PATHINFO_EXTENSION ));
        switch( $ext )
        {
            case 'jpg':
            case 'jpeg':
                $mime = 'image/jpg';
                break;

            case 'png';
                $mime = 'image/png';
                break;

            case 'gif';
            default:
                $mime = 'image/gif';
                break;
        }
        return $mime;
    }
}